package com.gitee.vueantd.common.utils.download;

import lombok.extern.log4j.Log4j2;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.Resource;
import org.springframework.http.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

@Log4j2
public class HttpDownloadUtil {
  public static long[] setResponseHeader(HttpServletRequest request, HttpServletResponse response, long lTotalLength) throws Exception {
    if (lTotalLength <= 0L) {
      return null;
    }
    long start = 0;
    long end = lTotalLength - 1;
    long[] range = parseRangeBytes(request);
    if (range != null) {
      start = range[0] > 0L ? range[0] : start;
      end = range[1] > 0L ? range[1] : end;
      response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
      response.addHeader("Content-Range", "bytes " + start + "-" + Math.max(start, end) + "/" + lTotalLength);
    } else {
      response.setStatus(HttpServletResponse.SC_OK);
    }

    response.addHeader("Accept-Ranges", "bytes");
    response.addHeader("Content-Length", Long.toString(end - start + 1));

    long[] rangePos = new long[2];

    rangePos[0] = start;
    rangePos[1] = end;
    return rangePos;
  }

  public static long[] parseRangeBytes(HttpServletRequest request) {
    String range = request.getHeader("Range");
    if (range != null) {
      int index = range.indexOf("bytes");
      if (index >= 0) {
        long[] rangePos = new long[2];
        range = range.substring(6);
        index = range.indexOf("-");
        rangePos[0] = index == 0 ? 0 : Long.parseLong(range.substring(0, index));
        range = range.substring(index + 1);
        if (range.length() == 0) {
          rangePos[1] = -1;
        } else {
          index = range.indexOf(",");
          rangePos[1] = index < 0 ? Long.parseLong(range) : Long.parseLong(range.substring(0, index));
        }
        return rangePos;
      }
    }
    return null;
  }

  public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, BandWidthLimiter limiter) throws Exception {
    downloadCommanderFile(request, response, file.getAbsolutePath(), limiter);
  }

  public static void downloadCommanderFile(HttpServletRequest request, HttpServletResponse response, String fileName, BandWidthLimiter limiter) throws Exception {
    List<String> fileNameList = new ArrayList();
    fileNameList.add(fileName);
    downloadFile(request, response, fileNameList, limiter);
  }

  public static void downloadFile(HttpServletRequest request, HttpServletResponse response, List<String> fileNameList, BandWidthLimiter limiter) throws Exception {
    try (OutputStream outputStream = response.getOutputStream()) {
      HttpFileDownloadUtil httpFileDownloadUtil = new HttpFileDownloadUtil();
      httpFileDownloadUtil.openFileList(fileNameList);
      long[] range = setResponseHeader(request, response, httpFileDownloadUtil.getLength());
      if (range != null) {
        MediaType mediaType = MediaTypeFactory.getMediaType(fileNameList.get(0)).orElse(MediaType.APPLICATION_OCTET_STREAM);
        response.setContentType(mediaType.toString());
        httpFileDownloadUtil.readContent(outputStream, range[0], range[1], limiter);
      }
    }
  }

  public static void downloadResourceFile(HttpServletRequest request, HttpServletResponse response, Resource resource) throws Exception {
    try (InputStream inputStream = resource.getInputStream();
         OutputStream outputStream = response.getOutputStream()) {
      IOUtils.copy(inputStream, outputStream);
    }
  }

  public static void downloadFile(String filePath, HttpServletRequest request, HttpServletResponse response, Integer startByte, Integer endByte, BandWidthLimiter limiter) throws Exception {
    List<String> fileNameList = new ArrayList();
    fileNameList.add(filePath);
    try (OutputStream outputStream = response.getOutputStream()) {
      HttpFileDownloadUtil httpFileDownloadUtil = new HttpFileDownloadUtil();
      httpFileDownloadUtil.openFileList(fileNameList);
      endByte = endByte == -1 ? (int) FileUtils.getFile(filePath).length() : endByte;
      long[] range = setResponseHeader(request, response, endByte - startByte + 1);
      if (range != null) {
        httpFileDownloadUtil.readContent(outputStream, startByte + range[0], endByte + range[1], limiter);
      }
    }
  }

  public static ResponseEntity downloadFile(String path) throws Exception {
    File file = new File(path);
    HttpHeaders headers;
    headers = new HttpHeaders();
    String filename = new String(path.getBytes("utf-8"), "ISO8859-1");
    headers.setContentDispositionFormData("attachment", filename);
    MediaType mediaType = MediaTypeFactory.getMediaType(path).orElse(MediaType.APPLICATION_OCTET_STREAM);
    headers.setContentType(mediaType);
    byte[] readBytes = FileUtils.readFileToByteArray(file);
    return new ResponseEntity<byte[]>(readBytes, headers, file.exists() ? HttpStatus.CREATED : HttpStatus.NO_CONTENT);
  }
}
